package com.calendar.widget;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
import android.widget.Toast;

import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import com.calendar.add.AddView;
import com.calendar.backend.Events;
import com.calendar.day.DayView;
import com.calendar.month.CalendarView;
import com.calendar.backend.Event;

public class CalendarWidget extends AppWidgetProvider {

	private static String ACTION_REFRESH = "Refresh_cal_widget_action";
	private static String EVENT_ID = "eventID";
	private static String MONTH = "month";
	private static String DAY = "day";
	private static String YEAR = "year";

	private Calendar cal;
	private RemoteViews remoteView;
	private boolean[] hasEvent;
	private boolean hasAllDayEvents;
	private boolean hasUpcomingEvents;
	private int numEvents;
	private Vector<Event> events;
	private Vector<Event> allDayEvents;
	private Vector<Event> upcomingEvents;
	private Events eventFinder;

	public CalendarWidget() {
		cal = Calendar.getInstance();
		hasEvent = new boolean[5];
		for (int i = 0; i < hasEvent.length; i++) {
			hasEvent[i] = false;
		}
		hasAllDayEvents = false;
		hasUpcomingEvents = false;
		numEvents = 0;
	}

	@Override
	public void onEnabled(Context context) {
		remoteView = new RemoteViews(context.getPackageName(), R.layout.main);
		// Load events.
		cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal
				.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
		eventFinder = new Events();
		events = eventFinder.findEvents(context, cal.getTimeInMillis(), cal
				.getTimeInMillis() + 86400000);
		numEvents = events.size();
		if (numEvents > 0) {
			allDayEvents = getAllDayEvents(events);
			if (!allDayEvents.isEmpty()) {
				hasAllDayEvents = true;
			}
			upcomingEvents = getUpcomingEvents(events);
			if (!upcomingEvents.isEmpty()) {
				hasUpcomingEvents = true;
			}
		}

		// android.util.Log.i("Calendar", "onEnable - Num Events: " +
		// numEvents);

		for (int i = 0; i < hasEvent.length; i++) {
			if (i >= numEvents) {
				setTextViewText(i, "");
				hasEvent[i] = false;
			} else if (hasAllDayEvents && i < allDayEvents.size()) {
				String text = formatAllDayEventString(allDayEvents.get(i));
				setTextViewText(i, text);
				setEventColor(i, allDayEvents.get(i));
				hasEvent[i] = true;
			} else if (hasUpcomingEvents && hasAllDayEvents) {
				int temp = i - allDayEvents.size();
				if (temp < upcomingEvents.size()) {
					String text = formatEventString(upcomingEvents.get(temp));
					setTextViewText(i, text);
					setEventColor(i, upcomingEvents.get(temp));
					hasEvent[i] = true;
				} else {
					setEventColor(i, null);
					setTextViewText(i, "");
					hasEvent[i] = false;
				}
			} else if (hasUpcomingEvents && i < upcomingEvents.size()) {
				String text = formatEventString(upcomingEvents.get(i));
				setTextViewText(i, text);
				setEventColor(i, upcomingEvents.get(i));
				hasEvent[i] = true;
			} else {
				setEventColor(i, null);
				setTextViewText(i, "");
				hasEvent[i] = false;
			}
		}
		super.onEnabled(context);
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {

		remoteView = new RemoteViews(context.getPackageName(), R.layout.main);

		// Load events.
		cal = Calendar.getInstance();
		cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal
				.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
		eventFinder = new Events();
		events = eventFinder.findEvents(context, cal.getTimeInMillis(), cal
				.getTimeInMillis() + 86400000);
		numEvents = events.size();

		if (numEvents > 0) {
			allDayEvents = getAllDayEvents(events);
			if (!allDayEvents.isEmpty()) {
				hasAllDayEvents = true;
			}
			upcomingEvents = getUpcomingEvents(events);
			if (!upcomingEvents.isEmpty()) {
				hasUpcomingEvents = true;
			}
			android.util.Log.i("Calendar", "onUpate - Num Events: " + numEvents
					+ ", " + upcomingEvents.size());
		}
		
		Vector<Event> display = new Vector<Event>();
		for (int i = 0; i < hasEvent.length; i++) {
			if (i >= numEvents) {
				setTextViewText(i, "");
				setEventColor(i, null);
				hasEvent[i] = false;
			} else if (hasAllDayEvents && i < allDayEvents.size()) {
				String text = formatAllDayEventString(allDayEvents.get(i));
				// remoteView.setInt(R.id.Event1, "setBackgroundColor",
				// android.graphics.Color.BLACK);
				setTextViewText(i, text);
				setEventColor(i, allDayEvents.get(i));
				hasEvent[i] = true;
				display.add(allDayEvents.get(i));
			} else if (hasUpcomingEvents && hasAllDayEvents) {
				int temp = i - allDayEvents.size();
				if (temp < upcomingEvents.size()) {
					String text = formatEventString(upcomingEvents.get(temp));
					// remoteView.setInt(R.id.Event1, "setBackgroundColor",
					// android.graphics.Color.BLACK);
					setTextViewText(i, text);
					setEventColor(i, upcomingEvents.get(temp));
					hasEvent[i] = true;
					display.add(upcomingEvents.get(temp));
				} else {
					setEventColor(i, null);
					setTextViewText(i, "");
					hasEvent[i] = false;
				}
			} else if (hasUpcomingEvents && !hasAllDayEvents
					&& i < upcomingEvents.size()) {
				String text = formatEventString(upcomingEvents.get(i));
				// remoteView.setInt(R.id.Event1, "setBackgroundColor",
				// android.graphics.Color.BLACK);
				setTextViewText(i, text);
				setEventColor(i, upcomingEvents.get(i));
				hasEvent[i] = true;
				display.add(upcomingEvents.get(i));
			} else {
				setEventColor(i, null);
				setTextViewText(i, "");
				hasEvent[i] = false;
			}
		}
		Intent monthIntent = new Intent(context, CalendarView.class);
		PendingIntent pendingMonthIntent = PendingIntent.getActivity(context,
				0, monthIntent, 0);

		Intent dayIntent = new Intent(context, DayView.class);
		dayIntent.putExtra(DAY, Calendar.getInstance().get(
				Calendar.DAY_OF_MONTH));
		dayIntent.putExtra(MONTH, Calendar.getInstance().get(Calendar.MONTH));
		dayIntent.putExtra(YEAR, Calendar.getInstance().get(Calendar.YEAR));
		PendingIntent pendingDayIntent = PendingIntent.getActivity(context, 0,
				dayIntent, PendingIntent.FLAG_UPDATE_CURRENT);

		Intent addIntent = new Intent(context, AddView.class);
		addIntent.setAction("Add" + Math.random());
		addIntent.putExtra(DAY, Calendar.getInstance().get(
				Calendar.DAY_OF_MONTH));
		addIntent.putExtra(MONTH, Calendar.getInstance().get(Calendar.MONTH));
		addIntent.putExtra(YEAR, Calendar.getInstance().get(Calendar.YEAR));
		addIntent.putExtra(EVENT_ID, "null");
		PendingIntent pendingAddIntent = PendingIntent.getActivity(context, 0,
				addIntent, PendingIntent.FLAG_UPDATE_CURRENT);

		Intent refreshIntent = new Intent(context, CalendarWidget.class);
		refreshIntent.setAction(ACTION_REFRESH);

		PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(
				context, 0, refreshIntent, 0);

		String text = ""
				+ getWeekday()
				+ " "
				+ getMonth()
				+ " "
				+ android.text.format.DateFormat.format("dd, yyyy",
						new java.util.Date());
		remoteView.setTextViewText(R.id.Date, text);
		remoteView.setOnClickPendingIntent(R.id.MonthView, pendingMonthIntent);
		remoteView.setOnClickPendingIntent(R.id.Date, pendingDayIntent);

		android.util.Log.i("Calendar", "" + display.size());
		
		if (hasEvent[0]) {
			Intent event1Intent = new Intent(context, AddView.class);
			event1Intent.setAction("Edit" + Math.random());
			event1Intent.putExtra(DAY, cal.get(Calendar.DAY_OF_MONTH));
			event1Intent.putExtra(MONTH, cal.get(Calendar.MONTH));
			event1Intent.putExtra(YEAR, cal.get(Calendar.YEAR));
			event1Intent.putExtra(EVENT_ID, display.get(0).getEventID());
			PendingIntent pendingEvent1Intent = PendingIntent
					.getActivity(context, 0, event1Intent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			remoteView
					.setOnClickPendingIntent(R.id.Event1, pendingEvent1Intent);
		}
		if (hasEvent[1]) {
			Intent event2Intent = new Intent(context, AddView.class);
			event2Intent.setAction("Edit" + Math.random());
			event2Intent.putExtra(DAY, cal.get(Calendar.DAY_OF_MONTH));
			event2Intent.putExtra(MONTH, cal.get(Calendar.MONTH));
			event2Intent.putExtra(YEAR, cal.get(Calendar.YEAR));
			event2Intent.putExtra(EVENT_ID, display.get(1).getEventID());
			PendingIntent pendingEvent2Intent = PendingIntent
					.getActivity(context, 0, event2Intent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			remoteView
					.setOnClickPendingIntent(R.id.Event2, pendingEvent2Intent);
		}
		if (hasEvent[2]) {
			Intent event3Intent = new Intent(context, AddView.class);
			event3Intent.setAction("Edit" + Math.random());
			event3Intent.putExtra(DAY, cal.get(Calendar.DAY_OF_MONTH));
			event3Intent.putExtra(MONTH, cal.get(Calendar.MONTH));
			event3Intent.putExtra(YEAR, cal.get(Calendar.YEAR));
			event3Intent.putExtra(EVENT_ID, display.get(2).getEventID());
			PendingIntent pendingEvent3Intent = PendingIntent
					.getActivity(context, 0, event3Intent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			remoteView
					.setOnClickPendingIntent(R.id.Event3, pendingEvent3Intent);
		}
		if (hasEvent[3]) {
			Intent event4Intent = new Intent(context, AddView.class);
			event4Intent.setAction("Edit" + Math.random());
			event4Intent.putExtra(DAY, cal.get(Calendar.DAY_OF_MONTH));
			event4Intent.putExtra(MONTH, cal.get(Calendar.MONTH));
			event4Intent.putExtra(YEAR, cal.get(Calendar.YEAR));
			event4Intent.putExtra(EVENT_ID, display.get(3).getEventID());
			PendingIntent pendingEvent4Intent = PendingIntent
					.getActivity(context, 0, event4Intent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			remoteView
					.setOnClickPendingIntent(R.id.Event4, pendingEvent4Intent);
		}
		if (hasEvent[4]) {
			Intent event5Intent = new Intent(context, AddView.class);
			event5Intent.setAction("Edit" + Math.random());
			event5Intent.putExtra(DAY, cal.get(Calendar.DAY_OF_MONTH));
			event5Intent.putExtra(MONTH, cal.get(Calendar.MONTH));
			event5Intent.putExtra(YEAR, cal.get(Calendar.YEAR));
			event5Intent.putExtra(EVENT_ID, display.get(4).getEventID());
			PendingIntent pendingEvent5Intent = PendingIntent
					.getActivity(context, 0, event5Intent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			remoteView
					.setOnClickPendingIntent(R.id.Event5, pendingEvent5Intent);
		}
		remoteView.setOnClickPendingIntent(R.id.Add, pendingAddIntent);

		remoteView.setOnClickPendingIntent(R.id.Refresh, refreshPendingIntent);

		appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}

	@Override
	public void onReceive(Context context, Intent intent) {

		// v1.5 fix that doesn't call onDelete Action
		final String action = intent.getAction();
		if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
			final int appWidgetId = intent.getExtras().getInt(
					AppWidgetManager.EXTRA_APPWIDGET_ID,
					AppWidgetManager.INVALID_APPWIDGET_ID);
			if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
				this.onDeleted(context, new int[] { appWidgetId });
			}
		} else {
			if (intent.getAction().equals(ACTION_REFRESH)) {
				super.onReceive(context, intent);

				Toast.makeText(context, "Refreshing...", Toast.LENGTH_SHORT)
						.show();
				
//				Bundle extras = new Bundle();
//				extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
//				context.getContentResolver().startSync(null, extras);

				AppWidgetManager appWidgetManager = AppWidgetManager
						.getInstance(context);
				ComponentName thisAppWidget = new ComponentName(context
						.getPackageName(), CalendarWidget.class.getName());
				int[] appWidgetIds = appWidgetManager
						.getAppWidgetIds(thisAppWidget);

				onUpdate(context, appWidgetManager, appWidgetIds);
			}
			super.onReceive(context, intent);

		}
	}

	private void setTextViewText(int i, String details) {
		switch (i) {
		case 0:
			remoteView.setTextViewText(R.id.Event1, details);
		case 1:
			remoteView.setTextViewText(R.id.Event2, details);
		case 2:
			remoteView.setTextViewText(R.id.Event3, details);
		case 3:
			remoteView.setTextViewText(R.id.Event4, details);
		case 4:
			remoteView.setTextViewText(R.id.Event5, details);
		}
	}

	private void setEventColor(int i, Event event) {
		int color = android.graphics.Color.TRANSPARENT;
		if (event != null) {
			color = event.getColor();
		}
		switch (i) {
		case 0:
			remoteView.setInt(R.id.Event1Color, "setBackgroundColor", color);
		case 1:
			remoteView.setInt(R.id.Event2Color, "setBackgroundColor", color);
		case 2:
			remoteView.setInt(R.id.Event3Color, "setBackgroundColor", color);
		case 3:
			remoteView.setInt(R.id.Event4Color, "setBackgroundColor", color);
		case 4:
			remoteView.setInt(R.id.Event5Color, "setBackgroundColor", color);
		}
	}

	private String formatEventString(Event event) {
		String ret = "";
		Date sDate = new Date(event.getStartTime());
		Date eDate = new Date(event.getEndTime());
		boolean am = true;
		if (sDate.getHours() >= 12) {
			if (sDate.getHours() > 12) {
				ret += "" + (sDate.getHours() - 12);
			} else {
				ret += "" + 12;
			}
			am = false;
		} else {
			ret += "" + sDate.getHours();
		}
		if (sDate.getMinutes() < 10) {
			ret += ":0" + sDate.getMinutes();
		} else {
			ret += ":" + sDate.getMinutes();
		}
		if (am) {
			ret += "am - ";
		} else {
			ret += "pm - ";
		}
		if (eDate.getHours() >= 12) {
			if (eDate.getHours() > 12) {
				ret += "" + (eDate.getHours() - 12);
			} else {
				ret += "" + 12;
			}
			am = false;
		} else {
			ret += "" + eDate.getHours();
			am = true;
		}
		if (eDate.getMinutes() < 10) {
			ret += ":0" + eDate.getMinutes();
		} else {
			ret += ":" + eDate.getMinutes();
		}
		if (am) {
			ret += "am \n\t\t\t\t";
		} else {
			ret += "pm \n\t\t\t\t";
		}
		if (event.getEventTitle().length() < 30) {
			ret += event.getEventTitle();
		} else {
			ret += event.getEventTitle().substring(0, 30) + "...";
		}
		return ret;
	}

	private String formatAllDayEventString(Event event) {
		String ret = "All day: ";
		if (event.getEventTitle().length() < 30) {
			ret += event.getEventTitle();
		} else {
			ret += event.getEventTitle().substring(0, 30) + "...";
		}
		return ret;
	}

	private String getWeekday() {
		String weekday = "error";
		int day = Calendar.getInstance().getTime().getDay() + 1;
		// Log.i("Calendar", "Day: " + day);
		switch (day) {
		case Calendar.SUNDAY:
			weekday = "Sunday";
			break;
		case Calendar.MONDAY:
			weekday = "Monday";
			break;
		case Calendar.TUESDAY:
			weekday = "Tuesday";
			break;
		case Calendar.WEDNESDAY:
			weekday = "Wednesday";
			break;
		case Calendar.THURSDAY:
			weekday = "Thursday";
			break;
		case Calendar.FRIDAY:
			weekday = "Friday";
			break;
		case Calendar.SATURDAY:
			weekday = "Saturday";
			break;
		}
		return weekday;
	}

	private String getMonth() {
		String month = "error";
		int monthNum = cal.get(Calendar.MONTH);
		// Log.i("Calendar", "Month: " + monthNum);
		switch (monthNum) {
		case Calendar.JANUARY:
			month = "January";
			break;
		case Calendar.FEBRUARY:
			month = "Febuary";
			break;
		case Calendar.MARCH:
			month = "March";
			break;
		case Calendar.APRIL:
			month = "April";
			break;
		case Calendar.MAY:
			month = "May";
			break;
		case Calendar.JUNE:
			month = "June";
			break;
		case Calendar.JULY:
			month = "July";
			break;
		case Calendar.AUGUST:
			month = "August";
			break;
		case Calendar.SEPTEMBER:
			month = "September";
			break;
		case Calendar.OCTOBER:
			month = "October";
			break;
		case Calendar.NOVEMBER:
			month = "November";
			break;
		case Calendar.DECEMBER:
			month = "December";
			break;
		}
		return month;
	}

	private Vector<Event> getAllDayEvents(Vector<Event> event) {
		Vector<Event> temp = new Vector<Event>();
		for (Event eve : event) {
			if (eve.getAllDay()) {
				temp.add(eve);
			}
		}
		return temp;
	}

	private Vector<Event> getUpcomingEvents(Vector<Event> event) {
		Vector<Event> temp = new Vector<Event>();
		// long currentTime = Calendar.getInstance().getTimeInMillis();
		long currentTime = System.currentTimeMillis();
		Date curr = new Date(currentTime);
		Date date;
		for (Event eve : event) {
			date = new Date(eve.getEndTime());
			if (!eve.getAllDay() && date.getHours() > curr.getHours()) {
				temp.add(eve);
			} else if (!eve.getAllDay() && date.getHours() == curr.getHours()
					&& date.getMinutes() > curr.getMinutes()) {
				temp.add(eve);
			}
		}
		android.util.Log.i("Calendar", "Num: " + temp.size());
		if (temp.size() > 1) {
			Vector<Event> sortedTemp = new Vector<Event>();

			for (int i = 0; i < 4; i++) {
				if (temp.isEmpty()) {
					break;
				}
				Event min = temp.get(0);
				int minIn = 0;
				Date minDate = new Date(min.getStartTime());
				Date check;
				for (int j = 1; j < temp.size(); j++) {
					check = new Date(temp.get(j).getStartTime());
					if (minDate.getHours() > check.getHours()) {
						min = temp.get(j);
						minIn = j;
						minDate = new Date(min.getStartTime());
					} else if (minDate.getHours() == check.getHours()
							&& minDate.getMinutes() > check.getMinutes()) {
						min = temp.get(j);
						minIn = j;
						minDate = new Date(min.getStartTime());
					}
				}
				sortedTemp.add(temp.remove(minIn));
			}
			if (temp.size() > 0) {
				sortedTemp.add(temp.remove(0));
			}

			temp = sortedTemp;
		}

		return temp;
	}
}